import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { HttpService } from '@nestjs/axios';
import { firstValueFrom, timeout, retry } from 'rxjs';
import { AxiosResponse, AxiosError, AxiosRequestConfig } from 'axios';
import { ProxyConfigService, ProxyMode } from '../config/proxy.config';
import { CopilotAdapter, CopilotRequest, CopilotResponse } from '../adapters/copilot.adapter';
import { CreateMessageDto, MessageResponseDto, CountTokensDto, CountTokensResponseDto } from '../dto/messages.dto';
import { AnthropicRequestLog } from '../interfaces/anthropic-api.interface';
import { TokenManagerService } from './token-manager.service';
import { CopilotRequestLoggerService } from './copilot-request-logger.service';
import { HttpsProxyAgent } from 'https-proxy-agent';
import { HttpProxyAgent } from 'http-proxy-agent';

@Injectable()
export class ForwardingService {
  private readonly logger = new Logger(ForwardingService.name);

  constructor(
    private readonly httpService: HttpService,
    private readonly configService: ProxyConfigService,
    private readonly copilotAdapter: CopilotAdapter,
    private readonly tokenManager: TokenManagerService,
    private readonly copilotLogger: CopilotRequestLoggerService
  ) {
    // 异步初始化GitHub token
    this.initializeGithubToken().catch(error => {
      this.logger.warn(`Failed to initialize GitHub token: ${error.message}`);
    });
  }

  /**
   * 初始化GitHub token
   */
  private async initializeGithubToken(): Promise<void> {
    const copilotConfig = await this.configService.getCopilotConfig();
    if (copilotConfig.authToken) {
      this.copilotAdapter.initializeGithubToken(copilotConfig.authToken);
      this.logger.log('GitHub token initialized for automatic refresh');
    } else {
      this.logger.warn('GitHub token not configured. Token refresh will not work.');
    }
  }

  /**
   * 转发消息请求
   */
  async forwardMessageRequest(
    createMessageDto: CreateMessageDto, 
    requestInfo: Partial<AnthropicRequestLog>
  ): Promise<MessageResponseDto> {
    // 使用传入的requestId，如果没有则创建新的
    const requestId = requestInfo.requestId || this.copilotLogger.createRequestContext();
    const startTime = Date.now();
    
    const mode = this.configService.getProxyMode();
    
    if (mode === ProxyMode.MOCK) {
      throw new Error('This service should only be used for forwarding, not mock responses');
    }

    try {
      // 简化的控制台日志
      this.logger.log(`Forwarding request [${requestId}] to Copilot API`);
      
      // 记录客户端请求接收阶段
      await this.copilotLogger.logClientRequest(requestId, {
        headers: requestInfo.headers || {},
        body: createMessageDto,
        method: 'POST',
        url: '/v1/messages',
        timestamp: new Date()
      });
      
      // 详细的文件日志
      // 向后兼容：简化日志记录
      this.logger.log(`Request forwarding started for model: ${createMessageDto.model}`);
      
      // 转换请求格式
      const conversionStartTime = Date.now();
      const copilotRequest = await this.copilotAdapter.convertAnthropicToCopilot(createMessageDto, requestId);
      const conversionDuration = Date.now() - conversionStartTime;
      
      await this.copilotLogger.logConversionComplete(
        requestId,
        'ForwardingService',
        'Anthropic',
        'Copilot',
        {
          originalRequest: {
            model: createMessageDto.model,
            messageCount: createMessageDto.messages.length,
            hasSystem: !!createMessageDto.system,
            hasTools: !!createMessageDto.tools?.length
          },
          convertedRequest: {
            model: copilotRequest.model,
            messageCount: copilotRequest.messages.length,
            hasTools: !!copilotRequest.tools?.length
          }
        },
        conversionDuration
      );
      
      // 发送请求到 Copilot
      const copilotResponse = await this.sendToCopilot('/chat/completions', copilotRequest, requestInfo, requestId);
      
      // 转换响应格式
      const responseConversionStart = Date.now();
      const anthropicResponse = this.copilotAdapter.convertCopilotToAnthropic(copilotResponse, createMessageDto, requestId);
      const responseConversionDuration = Date.now() - responseConversionStart;
      
      await this.copilotLogger.logResponseConversion(
        requestId,
        'ForwardingService',
        'Converting Copilot response to Anthropic format',
        {
          copilotResponse: {
            id: copilotResponse.id,
            model: copilotResponse.model,
            choicesCount: copilotResponse.choices?.length || 0,
            usage: copilotResponse.usage
          },
          anthropicResponse: {
            id: anthropicResponse.id,
            model: anthropicResponse.model,
            contentBlocks: anthropicResponse.content?.length || 0,
            stopReason: anthropicResponse.stop_reason
          }
        },
        responseConversionDuration
      );
      
      const totalDuration = Date.now() - startTime;
      
      // 简化的控制台日志
      this.logger.log(`Request [${requestId}] completed successfully (${totalDuration}ms)`);
      
      // 详细的文件日志
      await this.copilotLogger.logRequestComplete(
        requestId,
        'ForwardingService',
        'Message request forwarded successfully',
        {
          responseId: anthropicResponse.id,
          model: anthropicResponse.model,
          usage: anthropicResponse.usage,
          stopReason: anthropicResponse.stop_reason
        },
        totalDuration
      );
      
      return anthropicResponse;
    } catch (error) {
      // 控制台错误日志保持不变
      this.logger.error(`Request [${requestId}] failed: ${error.message}`);
      
      // 详细的错误文件日志
      await this.copilotLogger.logErrorLegacy(
        requestId,
        'ForwardingService',
        'Failed to forward message request',
        error,
        {
          model: createMessageDto.model,
          errorType: error.constructor.name,
          duration: Date.now() - startTime
        }
      );
      
      throw this.handleForwardingError(error);
    }
  }

  /**
   * 转发令牌计数请求
   */
  async forwardCountTokensRequest(
    countTokensDto: CountTokensDto,
    requestInfo: Partial<AnthropicRequestLog>
  ): Promise<CountTokensResponseDto> {
    try {
      this.logger.log(`Forwarding count tokens request to Copilot API`);
      
      // Copilot API 可能不直接支持令牌计数，我们可以通过发送一个空的请求来估算
      // 或者使用本地估算逻辑
      const estimatedTokens = this.estimateTokenCount(countTokensDto);
      
      this.logger.log(`Estimated token count: ${estimatedTokens}`);
      
      return {
        input_tokens: estimatedTokens
      };
    } catch (error) {
      this.logger.error(`Failed to forward count tokens request: ${error.message}`, error.stack);
      throw this.handleForwardingError(error);
    }
  }

  /**
   * 创建代理配置
   */
  private createProxyConfig(copilotConfig: any): any {
    if (!copilotConfig.proxy?.enabled || !copilotConfig.proxy?.url) {
      return undefined;
    }

    try {
      const proxyUrl = new URL(copilotConfig.proxy.url);
      
      // 如果有用户名和密码，添加到 URL 中
      if (copilotConfig.proxy.username && copilotConfig.proxy.password) {
        proxyUrl.username = copilotConfig.proxy.username;
        proxyUrl.password = copilotConfig.proxy.password;
      }

      // 根据目标 API 的协议选择合适的代理 agent
      const targetUrl = new URL(copilotConfig.apiUrl);
      
      if (targetUrl.protocol === 'https:') {
        return new HttpsProxyAgent(proxyUrl.toString());
      } else {
        return new HttpProxyAgent(proxyUrl.toString());
      }
    } catch (error) {
      this.logger.warn(`Failed to create proxy config: ${error.message}`);
      return undefined;
    }
  }

  /**
   * 发送请求到 Copilot API
   */
  private async sendToCopilot(
    endpoint: string, 
    requestData: any, 
    requestInfo: Partial<AnthropicRequestLog>,
    requestId?: string
  ): Promise<CopilotResponse> {
    const copilotConfig = await this.configService.getCopilotConfig();
    const url = `${copilotConfig.apiUrl}${endpoint}`;
    const apiCallStartTime = Date.now();
    
    // 生成请求头部（使用最新的有效token）
    const headers = await this.copilotAdapter.generateRequestHeaders(copilotConfig);
    
    // 创建代理配置
    const proxyAgent = this.createProxyConfig(copilotConfig);
    
    // 记录API调用开始（如果有requestId）
    if (requestId) {
      await this.copilotLogger.logApiCallStart(
        requestId,
        'ForwardingService',
        url,
        {
          endpoint,
          requestSize: JSON.stringify(requestData).length,
          hasProxy: !!proxyAgent,
          timeout: copilotConfig.timeout
        }
      );
    }
    
    // 构建请求配置
    const requestConfig: AxiosRequestConfig = {
      headers,
      timeout: copilotConfig.timeout,
      validateStatus: (status) => status < 500, // 重试5xx错误
    };

    // 如果有代理配置，添加到请求中
    if (proxyAgent) {
      requestConfig.httpsAgent = proxyAgent;
      requestConfig.httpAgent = proxyAgent;
      this.logger.debug('Using proxy for Copilot API request', {
        proxyUrl: copilotConfig.proxy?.url,
        hasAuth: !!(copilotConfig.proxy?.username && copilotConfig.proxy?.password)
      });
    }
    
    // 简化的请求日志记录
    if (this.configService.shouldLogRequests()) {
      this.logger.debug(`API call to ${endpoint}`);
      
      // 详细信息记录到文件（如果有requestId）
      if (requestId) {
        await this.copilotLogger.logCopilotRequestLegacy({
          requestId,
          phase: 'api_call_start',
          service: 'ForwardingService',
          level: 'debug',
          message: 'Detailed API request information',
          data: {
            url,
            method: 'POST',
            headers: this.maskSensitiveHeaders(headers),
            requestBody: requestData,
            proxyEnabled: !!proxyAgent,
            requestSize: JSON.stringify(requestData).length
          }
        });
      }
    }

    try {
      const response: AxiosResponse<CopilotResponse> = await firstValueFrom(
        this.httpService.post(url, requestData, requestConfig).pipe(
          timeout({ each: copilotConfig.timeout }),
          retry({
            count: copilotConfig.retryAttempts,
            delay: (error, retryCount) => {
              this.logger.warn(`Request failed, retrying (${retryCount}/${copilotConfig.retryAttempts}): ${error.message}`);
              const delayTime = 1000 * Math.pow(2, retryCount - 1);
              return new Promise(resolve => setTimeout(resolve, delayTime));
            }
          })
        )
      );

      const apiCallDuration = Date.now() - apiCallStartTime;
      
      // 简化的响应日志
      if (this.configService.shouldLogResponses()) {
        this.logger.debug(`API response: ${response.status} (${apiCallDuration}ms)`);
      }
      
      // 记录API调用完成（如果有requestId）
      if (requestId) {
        await this.copilotLogger.logApiCallComplete(
          requestId,
          'ForwardingService',
          response.status,
          {
            responseHeaders: {
              'content-type': response.headers['content-type'],
              'x-ratelimit-remaining': response.headers['x-ratelimit-remaining']
            },
            responseSize: JSON.stringify(response.data).length,
            hasChoices: !!response.data.choices?.length,
            usage: response.data.usage
          },
          apiCallDuration
        );
        
        // 详细响应数据记录到文件
        if (this.configService.shouldLogResponses()) {
          await this.copilotLogger.logCopilotRequestLegacy({
            requestId,
            phase: 'api_call_complete',
            service: 'ForwardingService',
            level: 'debug',
            message: 'Detailed API response information',
            data: {
              status: response.status,
              headers: response.headers,
              responseBody: response.data
            },
            timing: { duration: apiCallDuration }
          });
        }
      }

      // 检查是否是错误响应
      if (response.status >= 400) {
        const errorData = response.data as any;
        throw new HttpException(
          {
            type: 'error',
            error: {
              type: this.mapHttpStatusToErrorType(response.status),
              message: errorData?.error?.message || `Copilot API returned status ${response.status}`
            }
          },
          response.status
        );
      }

      // 检查是否是流式响应
      const contentType = response.headers['content-type'] || '';
      if (contentType.includes('text/event-stream')) {
        // 解析 SSE 数据
        const sseData = typeof response.data === 'string' ? response.data : String(response.data);
        return this.parseSSEResponse(sseData);
      }

      return response.data;
    } catch (error) {
      const apiCallDuration = Date.now() - apiCallStartTime;
      
      if (error instanceof AxiosError) {
        // 简化的控制台错误日志
        this.logger.error(`Copilot API Error: ${error.response?.status || 'Network'} - ${error.message}`);
        
        // 详细错误记录到文件（如果有requestId）
        if (requestId) {
          await this.copilotLogger.logErrorLegacy(
            requestId,
            'ForwardingService',
            'Copilot API call failed',
            error,
            {
              httpStatus: error.response?.status,
              httpStatusText: error.response?.statusText,
              responseData: error.response?.data,
              duration: apiCallDuration,
              url: url
            }
          );
        }
        
        throw new HttpException(
          {
            type: 'error',
            error: {
              type: this.mapHttpStatusToErrorType(error.response?.status || 500),
              message: error.response?.data?.error?.message || error.message
            }
          },
          error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR
        );
      }
      
      // 记录非HTTP错误
      if (requestId) {
        await this.copilotLogger.logErrorLegacy(
          requestId,
          'ForwardingService',
          'Non-HTTP error during API call',
          error,
          { duration: apiCallDuration, url: url }
        );
      }
      
      throw error;
    }
  }

  /**
   * 估算令牌数量
   */
  private estimateTokenCount(countTokensDto: CountTokensDto): number {
    let totalText = '';
    
    // 从系统提示计算
    if (countTokensDto.system) {
      if (typeof countTokensDto.system === 'string') {
        totalText += countTokensDto.system;
      }
    }

    // 从消息计算
    countTokensDto.messages.forEach(message => {
      if (typeof message.content === 'string') {
        totalText += message.content;
      } else if (Array.isArray(message.content)) {
        totalText += message.content
          .filter(block => block.type === 'text')
          .map(block => block.text || '')
          .join(' ');
      }
    });

    // 简单估算：英文约4字符=1token，中文约1.5字符=1token
    const englishChars = (totalText.match(/[a-zA-Z0-9\s]/g) || []).length;
    const chineseChars = (totalText.match(/[\u4e00-\u9fff]/g) || []).length;
    const otherChars = totalText.length - englishChars - chineseChars;
    
    const estimatedTokens = Math.ceil(
      englishChars / 4 + 
      chineseChars / 1.5 + 
      otherChars / 3
    );

    return Math.max(1, estimatedTokens);
  }

  /**
   * 处理转发错误
   */
  private handleForwardingError(error: any): HttpException {
    if (error instanceof HttpException) {
      return error;
    }

    let statusCode = HttpStatus.INTERNAL_SERVER_ERROR;
    let errorType = 'api_error';
    let errorMessage = 'Failed to forward request to Copilot API';

    if (error.code === 'ECONNREFUSED') {
      statusCode = HttpStatus.SERVICE_UNAVAILABLE;
      errorType = 'api_error';
      errorMessage = 'Unable to connect to Copilot API';
    } else if (error.code === 'ENOTFOUND') {
      statusCode = HttpStatus.SERVICE_UNAVAILABLE;
      errorType = 'api_error';
      errorMessage = 'Copilot API endpoint not found';
    } else if (error.name === 'TimeoutError') {
      statusCode = HttpStatus.REQUEST_TIMEOUT;
      errorType = 'api_error';
      errorMessage = 'Request to Copilot API timed out';
    }

    return new HttpException(
      {
        type: 'error',
        error: {
          type: errorType,
          message: errorMessage
        }
      },
      statusCode
    );
  }

  /**
   * 映射 HTTP 状态码到错误类型
   */
  private mapHttpStatusToErrorType(status: number): string {
    switch (Math.floor(status / 100)) {
      case 4:
        if (status === 401) return 'authentication_error';
        if (status === 403) return 'permission_error';
        if (status === 404) return 'not_found_error';
        if (status === 429) return 'rate_limit_error';
        return 'invalid_request_error';
      case 5:
        return 'api_error';
      default:
        return 'api_error';
    }
  }

  /**
   * 掩码敏感头部信息
   */
  private maskSensitiveHeaders(headers: Record<string, string>): Record<string, string> {
    const masked = { ...headers };
    
    if (masked.authorization) {
      const auth = masked.authorization;
      if (auth.length > 20) {
        masked.authorization = auth.substring(0, 10) + '***' + auth.substring(auth.length - 4);
      } else {
        masked.authorization = '***';
      }
    }

    return masked;
  }

  /**
   * 解析 Server-Sent Events 响应
   */
  private parseSSEResponse(sseData: string): CopilotResponse {
    const lines = sseData.split('\n');
    let lastCompleteResponse: any = null;
    let accumulatedContent = '';
    
    for (const line of lines) {
      if (line.startsWith('data: ') && !line.includes('[DONE]')) {
        try {
          const jsonStr = line.substring(6); // 移除 "data: " 前缀
          const chunk = JSON.parse(jsonStr);
          
          if (chunk.choices && chunk.choices.length > 0) {
            const choice = chunk.choices[0];
            
            // 累积内容
            if (choice.delta && choice.delta.content) {
              accumulatedContent += choice.delta.content;
            }
            
            // 如果这是最后一个块（有 finish_reason），构建完整响应
            if (choice.finish_reason) {
              lastCompleteResponse = {
                id: chunk.id,
                object: 'chat.completion',
                created: chunk.created,
                model: chunk.model,
                choices: [{
                  index: 0,
                  message: {
                    role: 'assistant',
                    content: accumulatedContent
                  },
                  finish_reason: choice.finish_reason
                }],
                usage: chunk.usage
              };
            }
          }
        } catch (error) {
          this.logger.debug('Failed to parse SSE chunk', { line, error: error.message });
        }
      }
    }
    
    if (!lastCompleteResponse) {
      throw new Error('Failed to parse SSE response: no complete response found');
    }
    
    this.logger.debug('Parsed SSE response', {
      id: lastCompleteResponse.id,
      contentLength: accumulatedContent.length,
      finishReason: lastCompleteResponse.choices[0].finish_reason
    });
    
    return lastCompleteResponse;
  }

  /**
   * 检查转发服务状态
   */
  async checkForwardingHealth(): Promise<{ status: string; mode: string; copilotApi: string; tokenManager: any }> {
    const mode = this.configService.getProxyMode();
    const copilotConfig = await this.configService.getCopilotConfig();
    
    let copilotStatus = 'unknown';
    
    if (mode === ProxyMode.COPILOT) {
      try {
        // 简单的健康检查 - 尝试连接到 Copilot API
        const proxyAgent = this.createProxyConfig(copilotConfig);
        const requestConfig: AxiosRequestConfig = {
          timeout: 5000,
          validateStatus: () => true // 接受任何状态码
        };

        if (proxyAgent) {
          requestConfig.httpsAgent = proxyAgent;
          requestConfig.httpAgent = proxyAgent;
        }

        await firstValueFrom(
          this.httpService.get(`${copilotConfig.apiUrl}/`, requestConfig).pipe(timeout({ each: 5000 }))
        );
        copilotStatus = 'reachable';
      } catch (error) {
        copilotStatus = 'unreachable';
        this.logger.warn(`Copilot API health check failed: ${error.message}`);
      }
    }

    // 获取token管理器状态
    const tokenHealth = await this.tokenManager.checkHealth();
    
    return {
      status: mode === ProxyMode.COPILOT ? 'forwarding' : 'mock',
      mode: mode,
      copilotApi: copilotStatus,
      tokenManager: tokenHealth
    };
  }
}